package org.genntii.smgateway.filter;

import io.jsonwebtoken.Claims;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.genntii.smcommon.constant.ClientConstant;
import org.genntii.smcommon.constant.GatewayConstant;
import org.genntii.smcommon.exception.TokenException;
import org.genntii.smcommon.properties.JwtProperties;
import org.genntii.smcommon.utils.JwtUtil;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextImpl;
import org.genntii.smgateway.security.DBUserDetailsManager;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Objects;

@Component
@EnableConfigurationProperties(JwtProperties.class)
@RequiredArgsConstructor
@Slf4j
public class JwtAuthenticationFilter implements WebFilter {


    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private DBUserDetailsManager detailsManager;



    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst(jwtProperties.getUserTokenName());
        String client = exchange.getRequest().getHeaders().getFirst("Client-Name");
        log.info("获取用户信息");

        if (token == null){
            log.info("无用户凭证，进入下一个过滤器");
            return chain.filter(exchange);
        }
        Claims claims = null;


        try {
            if (Objects.equals(client, ClientConstant.ADMIN_CLIENT)){
                claims =  JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(),token);
            } else if (Objects.equals(client, ClientConstant.USER_CLIENT)){
                claims =JwtUtil.parseJWT(jwtProperties.getUserSecretKey(),token);
            } else if (Objects.equals(client, ClientConstant.DEVELOPER_CLIENT)){
                claims = JwtUtil.parseJWT(jwtProperties.getDevSecretKey(),token);
            } else {
                return chain.filter(exchange);
            }
        }catch (Exception e){
            throw new TokenException("token失效",401);
//            ServerHttpResponse response = exchange.getResponse();
//            ServerHttpResponse responseUnAuthentication = response.setStatusCode(HttpStatus.UNAUTHORIZED.is4xxClientError());
//            return chain.filter(exchange.mutate().response(responseUnAuthentication).build());
        }
        log.info("进行JWT鉴权");
        String username = (String) claims.get("username");
        UserDetails user = detailsManager.loadUserByUsername(username);
        log.info("将用户信息加入spring security上下文中");

        String id = String.valueOf(claims.get("id"));
//        exchange.mutate()
//                .request(b->b.header(GatewayConstant.USER_ID,id))
//                .build();


        ServerHttpRequest request = exchange.getRequest().mutate().header(GatewayConstant.USER_ID,id).build();
        log.info("将id加入请求头");

        Authentication auth = new UsernamePasswordAuthenticationToken(user,token,user.getAuthorities());
        SecurityContext context = new SecurityContextImpl(auth);
        return chain.filter(exchange.mutate().request(request).build()).contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(context)));

    }
}
